﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using ServerEngine;


namespace WorldOfMUDra
{
    public partial class Player
    {
        private string _name;
        private Area _location;
        private bool _loggedIn;

        readonly List<string> _visitedIDs = new List<string>();
        readonly List<string> _itemIDs = new List<string>();

        readonly Dictionary<string, ServerCommandFunction> _abilityLibrary = new Dictionary<string, ServerCommandFunction>();
        readonly Dictionary<string, ServerCommandFunction> _gainedAbilities = new Dictionary<string, ServerCommandFunction>();

        readonly Dictionary<string, IItem> _inventory = new Dictionary<string, IItem>();

        public Player(Server host, Socket sock, string name) 
            : base(host, sock)
        {
            _name = name;
            AddPlayerServerCommandActions();
        }

        public Player(Server host, Socket sock)
            : base(host, sock)
        {
            _name = "Guest";
            AddPlayerServerCommandActions();
        }

        private void AddPlayerServerCommandActions()
        {
            //this.ServerCommandActions.Add("whereami", new ServerCommandFunction(WhereAmICommand));
            ServerCommandActions.Add("login", LogInCommand);
            //this.ServerCommandActions.Add("moveto", new ServerCommandFunction(MoveToCommand));
            ServerCommandActions.Add("say", SayCommand);

            _abilityLibrary.Add("moveto", MoveToCommand);
            _abilityLibrary.Add("whereami", WhereAmICommand);
            _abilityLibrary.Add("lookaround", LookAroundCommand);
            _abilityLibrary.Add("lookat", LookAtCommand);
            _abilityLibrary.Add("inventory", InventoryCommand);
            _abilityLibrary.Add("pickup", PickUpCommand);
        }

        protected override void OnSocketClose()
        {
            Globals.CreateConfigFor(this);
        }

        /// <summary>
        /// Sends a list of inventory items to the client to be displayed however the client deems best.
        /// </summary>
        public void SendInventory()
        {
            string list = _inventory.Values.Aggregate("", (current, item) => current + (item.Name + " "));
            SendRawMessage(MudraProtocol.Inventory.ToString("d") + " " + list);
        }

        /// <summary>
        /// Tell the client to play a certain sound file, if the file exists.
        /// </summary>
        /// <param name="soundName">The name of the sound file to be played. DO NOT append a file extension (ie .mp3, .wav, etc).</param>
        /// <param name="loop">Whether the sound should be loop or not.</param>
        public void PlaySound(string soundName, bool loop)
        {
            string l = "0";
            if (loop) l = "1";
            SendRawMessage(MudraProtocol.Sound.ToString("d") + " " + soundName + " " + l);
        }

        public void AddItem(IItem item)
        {
            StackableItem loadedItem = item as StackableItem;
            if (loadedItem != null)
            {
                StackableItem t = (StackableItem)(loadedItem.Copy());
                t.Amount = 1;
                _inventory.Add(t.ID, t);
            }
            else
            {
                _inventory.Add(item.ID, item);
            }
        }

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public bool LoggedIn
        {
            get { return _loggedIn; }
        }

        public string Location
        {
            get { return _location.Description; }
        }

        public string LocationId
        {
            get { return _location.Id; }
        }

        new public void SendChatMessage(string msg)
        {
            if (msg != null) SendRawMessage(MudraProtocol.Chat.ToString("d") + " Someone " + msg);
        }

        public void SendChatMessage(string sender, string msg)
        {
            if (msg != null) SendRawMessage(MudraProtocol.Chat.ToString("d") + " " + sender + " " + msg);
        }

        public void WarpTo(Area area)
        {
            area.MoveHere(this);
        }

        public void MoveTo(string destinationName)
        {
            if (_location.LeadsTo(destinationName))
            {
                _location = _location.Places(destinationName);
            }
        }

        public void MoveTo(Area destination)
        {
            _location = destination;
        }

        public Area CurrentArea()
        {
            return _location;
        }

        public void AddVisitedArea(PlayerConfigFile pcf)
        {
            if (pcf.VisitedAreas == null) return;
            foreach (string aid in pcf.VisitedAreas)
            {
                Console.WriteLine("Adding area ID '"+aid.Trim()+"' from config.");
                _visitedIDs.Add(aid.Trim());
            }
            foreach (string id in pcf.ItemIDs) _itemIDs.Add(id);
        }

        public void AddVisitedArea(string area)
        {
            if (!_visitedIDs.Contains(area.Trim())) _visitedIDs.Add(area);
        }

        public string VisitedAreas
        {
            get
            {
                return string.Join(" ", _visitedIDs);
            }
        }

        public string ItemIDs
        {
            get
            {
                return string.Join(" ", _itemIDs);
            }
        }

        public string GainedAbilities
        {
            get
            {
                return string.Join(" ", _gainedAbilities.Keys);
            }
        }

        public bool HasVisited(Area a)
        {
            Console.WriteLine("Checking to see if "+_name+" has '"+a.Id+"'");
            return _visitedIDs.Contains(a.Id);
        }

        public bool HasPickedUp(IItem i)
        {
            return _itemIDs.Contains(i.ID);
        }

        public void GiveAbility(ServerCommandFunction ability, string name, string desc, string syntax, string keyword)
        {
            if (!_gainedAbilities.ContainsKey(keyword))
            {
                _gainedAbilities.Add(keyword, ability);
                SendWorldMessage("You gained the ability: " + name + "! "+desc+"\nThe syntax is: "+syntax);
            }
            if (!ServerCommandActions.ContainsKey(keyword))
            {
                ServerCommandActions.Add(keyword, ability);
            }
        }

        public void LoadAbility(ServerCommandFunction ability, string keyword)
        {
            _gainedAbilities.Add(keyword, ability);
            ServerCommandActions.Add(keyword, ability);
        }

        public void LoadAbilities(PlayerConfigFile pcf)
        {
            foreach (string ability in pcf.Abilities)
            {
                if (_abilityLibrary.ContainsKey(ability)) LoadAbility(_abilityLibrary[ability], ability);
            }
        }
    }
}
